package com.atguigu.lease.admin.service.impl;

import com.atguigu.lease.admin.mapper.*;
import com.atguigu.lease.admin.service.*;
import com.atguigu.lease.model.bean.*;
import com.atguigu.lease.model.dto.RoomItemQueryDto;
import com.atguigu.lease.model.dto.RoomSubmitDto;
import com.atguigu.lease.model.enums.ItemType;
import com.atguigu.lease.model.vo.AttrValueVo;
import com.atguigu.lease.model.vo.RoomDetailVo;
import com.atguigu.lease.model.vo.RoomItemVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
* @author 1
* @description 针对表【room_info(房间信息表)】的数据库操作Service实现
* @createDate 2025-09-22 17:18:51
*/
@Service
public class RoomInfoServiceImpl extends ServiceImpl<RoomInfoMapper, RoomInfo>
    implements RoomInfoService{
    //装配房间关联数据的业务类
    @Autowired
    private RoomFacilityService roomFacilityService;
    @Autowired
    private RoomLabelService roomLabelService;
    @Autowired
    private RoomAttrValueService   roomAttrValueService;
    @Autowired
    private GraphInfoService graphInfoService;
    @Autowired
    private RoomLeaseTermService roomLeaseTermService;
    @Autowired
    private RoomPaymentTypeService roomPaymentTypeService;
    @Autowired
    @Lazy //懒加载： ioc容器初始化时 不需要从容器中自动装配apartmentInfoService对象
    // 当 当前对象业务方法使用了apartmentInfoService对象时 才从ioc容器中获取对象使用
    private ApartmentInfoService apartmentInfoService;
    @Override
    public Page<RoomItemVo> pageItem(RoomItemQueryDto queryDto) {
        //使用queryWrapper代替mybatis中的自定义sql
        QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.hasText(queryDto.getProvinceId()) , "t3.province_id" ,
                queryDto.getProvinceId());
        queryWrapper.eq(StringUtils.hasText(queryDto.getCityId()) , "t3.city_id" ,
                queryDto.getCityId());
        queryWrapper.eq(StringUtils.hasText(queryDto.getDistrictId()) , "t3.district_id" ,
                queryDto.getDistrictId());
        queryWrapper.eq(StringUtils.hasText(queryDto.getApartmentId()) , "t1.apartment_id" ,
                queryDto.getApartmentId());
        queryWrapper.eq("t1.is_deleted" , 0 );

        Page<RoomItemVo> page =   baseMapper.selectPageItem(new Page<>(queryDto.getCurrent(), queryDto.getSize()),
                queryWrapper);
        return page;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveOrUpdateRoomSubmitDto(RoomSubmitDto roomSubmitDto) {
        //1、判断是新增还是更新：
        boolean isUpdate = roomSubmitDto.getId()!=null;
        //2、新增或更新 房间信息：
        saveOrUpdate(roomSubmitDto);
        Long roomId = roomSubmitDto.getId();//获取房间id
        //3、如果是更新：需要先删除房间所有的关联数据
        if(isUpdate){
            removeRoomDatas(roomId);
        }
        //4、无论新增还是更新： 保存本次页面提交的房间的关联数据
        //保存房间的配套关联数据
        List<Integer> facilityInfoIds = roomSubmitDto.getFacilityInfoIds();
        if(!CollectionUtils.isEmpty(facilityInfoIds)) {
            List<RoomFacility> roomFacilities = facilityInfoIds
                    .stream()
                    .map(facilityId -> {
                        RoomFacility roomFacility = new RoomFacility();
                        roomFacility.setRoomId(roomId);
                        roomFacility.setFacilityId(facilityId.longValue());
                        return roomFacility;
                    })
                    .collect(Collectors.toList());
            roomFacilityService.saveBatch(roomFacilities);
        }

        //保存房间的属性值关联数据
        List<Integer> attrValueIds = roomSubmitDto.getAttrValueIds();
        if(!CollectionUtils.isEmpty(attrValueIds)) {
            List<RoomAttrValue> roomAttrValues = attrValueIds
                    .stream()
                    .map(attrValueId -> {
                        RoomAttrValue roomAttrValue = new RoomAttrValue();
                        roomAttrValue.setRoomId(roomId);
                        roomAttrValue.setAttrValueId(attrValueId.longValue());
                        return roomAttrValue;
                    })
                    .collect(Collectors.toList());
            roomAttrValueService.saveBatch(roomAttrValues);
        }
        //保存房间的标签关联数据
        List<Integer> labelInfoIds = roomSubmitDto.getLabelInfoIds();
        if(!CollectionUtils.isEmpty(labelInfoIds)) {
            List<RoomLabel> roomLabels = labelInfoIds.stream().map(labelInfoId -> {
                RoomLabel roomLabel = new RoomLabel();
                roomLabel.setRoomId(roomId);
                roomLabel.setLabelId(labelInfoId.longValue());
                return roomLabel;
            }).collect(Collectors.toList());
            roomLabelService.saveBatch(roomLabels);
        }

        //保存房间的可选租约关联数据
        List<Integer> leaseTermIds = roomSubmitDto.getLeaseTermIds();
        if(!CollectionUtils.isEmpty(leaseTermIds)) {
            List<RoomLeaseTerm> roomLeaseTerms = leaseTermIds.stream()
                    .map(leaseTermId -> {
                        RoomLeaseTerm roomLeaseTerm = new RoomLeaseTerm();
                        roomLeaseTerm.setRoomId(roomId);
                        roomLeaseTerm.setLeaseTermId(leaseTermId.longValue());
                        return roomLeaseTerm;
                    }).collect(Collectors.toList());
            roomLeaseTermService.saveBatch(roomLeaseTerms);
        }
        //保存房间的可选支付方式关联数据
        List<Integer> paymentTypeIds = roomSubmitDto.getPaymentTypeIds();
        if(!CollectionUtils.isEmpty(paymentTypeIds)) {
            List<RoomPaymentType> roomPaymentTypes = paymentTypeIds.stream()
                    .map(paymentTypeId -> {
                        RoomPaymentType roomPaymentType = new RoomPaymentType();
                        roomPaymentType.setRoomId(roomId);
                        roomPaymentType.setPaymentTypeId(paymentTypeId.longValue());
                        return roomPaymentType;
                    }).collect(Collectors.toList());
            roomPaymentTypeService.saveBatch(roomPaymentTypes);
        }

        //保存房间的图片列表:
        List<GraphInfo> graphInfos = roomSubmitDto.getGraphVoList();
        if(!CollectionUtils.isEmpty(graphInfos)) {
            graphInfos.forEach(graphInfo -> {
                //新增更新之前的删除 是逻辑删除！！ 表中被删除的数据仍然存在
                graphInfo.setId(null);//因为前端如果是更新房间，会将没有删除的图片对象(包含图片id)直接提交给后端
                graphInfo.setItemId(roomId);
                graphInfo.setItemType(ItemType.ROOM.getCode());
            });
            graphInfoService.saveBatch(graphInfos);
        }

    }

    private void removeRoomDatas(Long roomId) {
        //根据房间id删除配套关联数据
        roomFacilityService.remove(Wrappers.lambdaQuery(RoomFacility.class)
                .eq(RoomFacility::getRoomId, roomId));
        //根据房间id删除属性值关联数据
        roomAttrValueService.remove(Wrappers.lambdaQuery(RoomAttrValue.class)
                .eq(RoomAttrValue::getRoomId, roomId));
        //根据房间id删除标签关联数据
        roomLabelService.remove(Wrappers.lambdaQuery(RoomLabel.class)
                .eq(RoomLabel::getRoomId, roomId));
        //根据房间id删除可选租约关联数据
        roomLeaseTermService.remove(Wrappers.lambdaQuery(RoomLeaseTerm.class)
                .eq(RoomLeaseTerm::getRoomId, roomId));
        //根据房间id删除可选支付方式关联数据
        roomPaymentTypeService.remove(Wrappers.lambdaQuery(RoomPaymentType.class)
                .eq(RoomPaymentType::getRoomId, roomId));
        //根据房间id+类型 删除房间的图片列表
        graphInfoService.remove(Wrappers.lambdaQuery(GraphInfo.class)
                .eq(GraphInfo::getItemId, roomId)
                .eq(GraphInfo::getItemType , ItemType.ROOM)
        );
    }

    @Autowired
    RoomLabelMapper roomLabelMapper;
    @Autowired
    RoomFacilityMapper roomFacilityMapper;
    @Autowired
    RoomAttrValueMapper roomAttrValueMapper;
    @Autowired
    RoomLeaseTermMapper roomLeaseTermMapper;
    @Autowired
    RoomPaymentTypeMapper roomPaymentTypeMapper;
//    @Autowired
//    GraphInfoMapper graphInfoMapper;
    @Override
    public RoomDetailVo getDetailById(Long id) {
        //创建vo对象！！ 一步步的为它查询数据 比设置给他
        RoomDetailVo roomDetailVo = new RoomDetailVo();
        //1、根据id查询房间信息
        RoomInfo roomInfo = getById(id);
        BeanUtils.copyProperties(roomInfo, roomDetailVo);//拷贝相同的属性

        //2、根据房间的公寓id查询公寓信息
        ApartmentInfo apartmentInfo = apartmentInfoService.getById(roomInfo.getApartmentId());
        roomDetailVo.setApartmentInfo(apartmentInfo);

        //3、根据房间id查询关联数据
        //3.1 查询房间的标签数据
        List<LabelInfo> labelInfoList = roomLabelMapper.selectRoomLabelsByRoomId(id);
        roomDetailVo.setLabelInfoList(labelInfoList);
        //3.2 查询房间的配套数据
        List<FacilityInfo> facilityInfoList = roomFacilityMapper
                .selectFacilityInfosByRoomId(id);
        roomDetailVo.setFacilityInfoList(facilityInfoList);
        //3.4 查询房间的可选租约数据
        List<LeaseTerm> leaseTermList = roomLeaseTermMapper
                .selectleaseTermListByRoomId(id);
        roomDetailVo.setLeaseTermList(leaseTermList);
        //3.5 查询房间的可选支付方式数据
        List<PaymentType> paymentTypeList = roomPaymentTypeMapper
                .selectpaymentTypeListByRoomId(id);
        roomDetailVo.setPaymentTypeList(paymentTypeList);
        //3.3 查询房间的属性和键数据: 需要三表联查
        // 使用roomid 查询 room_attr_value表中的 attr_value_id ，再根据attr_value_id 联查attr_value表中的数据
        // 最后 根据attr_value表 attr_key_id 联查 attr_key表 查询键的名称
        List<AttrValueVo> attrValueVoList = roomAttrValueMapper
                .selectattrValueVoListByRoomId(id);
        roomDetailVo.setAttrValueVoList(attrValueVoList);
        //3.6 查询房间的图片列表
        List<GraphInfo> graphInfos = graphInfoService.list(Wrappers.lambdaQuery(GraphInfo.class)
                .eq(GraphInfo::getItemId, id)
                .eq(GraphInfo::getItemType, ItemType.ROOM)
        );
        roomDetailVo.setGraphVoList(graphInfos);


        return roomDetailVo;
    }
    //AB测试： 测试接口 或者业务时 使用 正反数据测试
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeRoomInfoById(Integer id) {
        //1、删除房间数据
        // mp 生成sql时，使用预编译的方式处理，会将 传入的参数转为 实体类对应属性的 类型
        //  避免索引失效(如果操作的列 有索引，查询时 交给mysql的sql语句 有类型转换 会导致索引失效！)
        // 数值型的包装类：传参时 需要保持类型一致！！！
        removeById(id.longValue());//room_info
        //2、删除房间关联数据
        removeRoomDatas(id.longValue());
    }

    //查询公寓下可用的房间列表
    @Override
    public List<RoomInfo> listBasicByApartmentId(Long apartmentId) {
        return baseMapper.selectBasicByApartmentId(apartmentId);
    }
}




